#pragma once

#include <mc_runtime.h>
#include <stdio.h>
#include <stdlib.h>


// MACA Runtime error messages
#ifdef __DRIVER_TYPES_H__
static const char *_mcGetErrorEnum(mcError_t error) {
  return mcGetErrorName(error);
}
#endif

#ifdef MCBLAS_API_H_
// mcBlas API errors
static const char *_mcGetErrorEnum(mcblasStatus_t error) {
  switch (error) {
    case MCBLAS_STATUS_SUCCESS:
      return "MCBLAS_STATUS_SUCCESS";

    case MCBLAS_STATUS_NOT_INITIALIZED:
      return "MCBLAS_STATUS_NOT_INITIALIZED";

    case MCBLAS_STATUS_ALLOC_FAILED:
      return "MCBLAS_STATUS_ALLOC_FAILED";

    case MCBLAS_STATUS_INVALID_VALUE:
      return "MCBLAS_STATUS_INVALID_VALUE";

    case MCBLAS_STATUS_ARCH_MISMATCH:
      return "MCBLAS_STATUS_ARCH_MISMATCH";

    case MCBLAS_STATUS_MAPPING_ERROR:
      return "MCBLAS_STATUS_MAPPING_ERROR";

    case MCBLAS_STATUS_EXECUTION_FAILED:
      return "MCBLAS_STATUS_EXECUTION_FAILED";

    case MCBLAS_STATUS_INTERNAL_ERROR:
      return "MCBLAS_STATUS_INTERNAL_ERROR";

    case MCBLAS_STATUS_NOT_SUPPORTED:
      return "MCBLAS_STATUS_NOT_SUPPORTED";

    case MCBLAS_STATUS_LICENSE_ERROR:
      return "MCBLAS_STATUS_LICENSE_ERROR";
  }

  return "<unknown>";
}
#endif

//#define checkGPUErrors(val) __check((val), #val, __FILE__, __LINE__)
#define checkGPUErrors(val) {} //TODO

template <typename T>
void __check(T result, char const *const func, const char *const file,
           int const line) {
  if (result) {
    fprintf(stderr, "MACA error at %s:%d code=%d(%s) \"%s\" \n", file, line,
            static_cast<unsigned int>(result), _mcGetErrorEnum(result), func);
    exit(EXIT_FAILURE);
  }
}

#define checkGPULastErrors() __checkLastError(__FILE__, __LINE__)

inline void __checkLastError(const char *const file, int const line) {
  mcError_t err = mcGetLastError();
  if (mcSuccess != err) {
    fprintf(stderr, "MACA error at %s:%d code=%d(%s) \n", file, line,
            static_cast<unsigned int>(err), mcGetErrorName(err));
    exit(EXIT_FAILURE);
  }
}
